package com.weng.coder.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.weng.coder.common.exception.ServiceException;
import com.weng.coder.common.utils.*;
import com.weng.coder.entity.*;
import com.weng.coder.mapper.*;
import com.weng.framework.core.model.ResponseData;
import com.weng.framework.dao.mybatis.model.page.PageModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Pattern;


/**
 * 项目 业务实现类
 *
 * @作者 wengzhonghui
 * @创建时间 2018-02-24 10:16:58
 */
@Slf4j
@Service("projectService")
public class ProjectServiceImpl  implements ProjectService {
	@Resource
	private ProjectMapper projectDao;
	@Autowired
	private CodeTableMapper codeTableDao;
	@Autowired
	private ColumnMapper columnDao;
	@Autowired
	private ColumnService columnService;
	@Autowired
	private FieldMapper fieldDao;

	@Resource
	private FieldService fieldService;
	@Resource
	private TemplateMapper templateDao;
	@Resource
	private NameRuleMapper nameRuleDao;
	@Resource
	private ProjectUserMapper projectUserDao;

	@Resource
	private ProjectUserService projectUserService;
	@Resource
	private CodeTableService codeTableService;
	@Resource
	private NameRuleService nameRuleService;
	@Resource
	private TemplateService templateService;
	
	@Transactional
	@Override
	public boolean copyProject(String projectId,String userId){
		
		Project oldProject = this.projectDao.selectById(projectId);
		QueryWrapper<Template> templateQw = new QueryWrapper();
		templateQw.eq("PROJECT_ID",projectId);
		List<Template> oldTemplateList = this.templateDao.selectList(templateQw);

		QueryWrapper<NameRule> nameRuleQw = new QueryWrapper();
		nameRuleQw.eq("PROJECT_ID",projectId);
		List<NameRule> oldNameRuleList = this.nameRuleDao.selectList(nameRuleQw);
		
		Project newProject = new Project(null, oldProject.getCode()+"_copy", oldProject.getName()+"_copy", oldProject.getStatus()
				, oldProject.getRemarks(), oldProject.getCompanyCode(), oldProject.getBaseProjectCode()
				, oldProject.getDbCategory(), oldProject.getDbUrl(), oldProject.getDbUsername()
				, oldProject.getDbPassword(), oldProject.getDbName(),oldProject.getApiPrefix()
				, Constants.IS_BUILD_IN_FALSE,oldProject.getPkg(),oldProject.getIsCatalog());
		newProject.setIsBuildIn(Constants.IS_BUILD_IN_FALSE);
		projectDao.insert(newProject);

		ProjectUser projectUser = new ProjectUser(newProject.getId(),userId, Constants.IS_OWNER_TRUE);
		projectUserDao.insert(projectUser);

		for(Template oldTemplate:oldTemplateList){
			Template newTemplate = new Template(null, oldTemplate.getCode(), oldTemplate.getName()
					, oldTemplate.getStatus(), newProject.getId()
					, oldTemplate.getRemarks(), oldTemplate.getContent(), oldTemplate.getPkg()
					, oldTemplate.getFilename(), oldTemplate.getExtension(), oldTemplate.getModualName());
			this.templateDao.insert(newTemplate);
		}
		for(NameRule oldNameRule : oldNameRuleList){
			NameRule newNameRule = new NameRule(null, oldNameRule.getRule(), oldNameRule.getExpression()
					, oldNameRule.getContent(), oldNameRule.getPosition(), oldNameRule.getCategory()
					, newProject.getId());
			this.nameRuleDao.insert(newNameRule);
		}
		return true;
	}
	public List<Project> findByIds(List<String> ids){
		return projectDao.selectBatchIds(ids);

	}
	/**
	 * Save
	 * @param t
	 */
	@Transactional
	@Override
	public Project save(Project t) {
			if(StringUtils.isEmpty(t.getId())){
					projectDao.insert(t);
			}else{
					projectDao.updateById(t);
			}
		return t;
	}

	@Override
	public ResponseData removeByIds(String ids) {
		String[] catalogIds = ids.split(",");
		this.projectDao.deleteBatchIds(Arrays.asList(catalogIds));
		return ResponseData.success();
	}

	

	@Override
	public List<Project> getProjectListByUser(String name, Boolean isBuildIn, String userId) {
		Project project = new Project();
		project.setName(name);
		project.setIsBuildIn(Constants.IS_BUILD_IN_FALSE);
		
		List<Project> list = this.projectDao.listByUser(name,userId);
		list = list == null ? new ArrayList<>() : list;
		
		//查询内容模板列表
		if(isBuildIn!=null && isBuildIn==true){
			project.setIsBuildIn(Constants.IS_BUILD_IN_TRUE);
			QueryWrapper<Project> queryWrapper = new QueryWrapper<>();
			queryWrapper.eq("IS_BUILD_IN", 1);
			if(StringUtils.isNotEmpty(name)){
				queryWrapper.like("NAME", name);
			}
			List<Project> buildInList = this.projectDao.selectList(queryWrapper);
			buildInList = buildInList == null ? new ArrayList<>() : buildInList;
			list.addAll(buildInList);
		}
		return list;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public IPage<Project> getDataByPage(int pageNo, int pageSize, String name,  String userId) {

		IPage<Project> page = new PageModel<>(pageNo,pageSize);
		List<Project> list =  projectDao.page(page,name, userId);
		page.setRecords(list);
		return page;
	}

	


	

	@Override
	public void delete(Project t) {
		projectDao.deleteById(t.getId());
	}
	

	@Override
	public Project getOne(String id) {
		
		return projectDao.selectById(id);

	}

	@Override
	public boolean exists(String id) {
		Project project = this.getOne(id);
		if(project == null){
			 return false;
		}else{
			return true;
		}
	}

	@Override
	public void delete(Iterable<Project> entities) {
		if(entities!=null){
			for(Project t:entities){
				projectDao.deleteById(t.getId());
			}
		}
	}

	@Override
	public void deleteByIds(String[] ids) {
		if(ids!=null && ids.length>0){
			for(String id:ids){
				projectDao.deleteById(id);
			}
		}
	}
	
	@Override
	public boolean synchronize(String projectId) throws ServiceException {
		// 1、根据项目id获取项目配置
		Project project = this.getOne(projectId);
		if (project==null || StringUtils.isEmpty(project.getDbUrl())
				|| StringUtils.isEmpty(project.getDbUsername())) {
			return false;
		}
		return this.synchronize(project);
	}
	
	@Override
	public boolean synchronize(Project project) throws ServiceException {
		// 1、根据项目id获取项目配置
		if (project==null) {
			return false;
		}

		// 2、创建数据库连接对象
		Connection connection = null;
		try {
			connection = JdbcGenerator.getConnection(project.getDbCategory(),project.getDbUrl(),
					project.getDbUsername(),project.getDbPassword());
		} catch (Exception e) { 
			e.printStackTrace();
			log.error("表同步时，数据库连接失败！项目ID：" + project.getId() + "，链接地址：" + project.getDbUrl() + "，用户名/密码："
					+ project.getDbUsername() + "/" + project.getDbPassword() + "。", e);
		}

		// 3、获取数据库的表格信息
		Map<String, String> newTables = null;
		try {
			newTables = JdbcGenerator.getTables(connection,project.getDbName());
		} catch (SQLException e) {
			log.error("表同步时，获取数据库的表格信息出错！项目ID：" + project.getId() + "。", e);
		}

		// 4、根据项目id获取项目表格信息
			QueryWrapper<CodeTable> qw = new QueryWrapper<>();
		qw.eq("PROJECT_ID",project.getId());
		List<CodeTable> oldTables = codeTableDao.selectList(qw);

		// 5、先更新或删除已有表格信息
		try {
			for (CodeTable table : oldTables) {
				if (newTables.containsKey(table.getCode())) {
					// 5.1、更新旧的表格、列、字段信息
					// 更新表
					String newRemark = newTables.get(table.getCode());
					table.setRemarks(newRemark);
					if(table.getArea()==null){
						table.setArea("system");
					}
					codeTableDao.insert(table);
					newTables.remove(table.getCode());// 删除map表记录
					// 更新列
					updateColumns(table, connection,project.getDbName());
				} else {// 如果没有，表示没有表格已经删除
					// 5.2、删除旧的表格、列、字段信息
					codeTableDao.deleteById(table.getId());
					columnService.deleteByTableId(table.getId());
					fieldService.deleteByTableId(table.getId());
				}
			}
		} catch (Exception e) {
			log.error("表同步时，更新或删除已有表格信息出错！项目ID：" + project.getId() + "。", e);
		}

		// 6、全新新增表、列、字段信息
		try {
			Set<String> codeSet = newTables.keySet();
			int i=0;
			for (String code : codeSet) {

				CodeTable table = new CodeTable();
				table.setCode(code);
				table.setProjectId(project.getId());
				table.setRemarks("" + newTables.get(code));
				table.setStatus(Constants.TABLE_NOT_SET);
				codeTableDao.insert(table);// 添加表

				// 更新列
				updateColumns(table, connection,project.getDbName());

				// 清理旧的残留字段
				fieldDao.deleteOldFields(table.getId());
				i++;
				if(i>20){
					// 关闭数据库连接
					try {
						connection.close();
					} catch (SQLException e) {
						log.error("表同步时，关闭数据库连接失败！", e);
					}
					return true;
				}
			}
		} catch (Exception e) {
			log.error("表同步时，全新新增表、列、字段信息出错！项目ID：" + project.getId() + "。", e);
			return true;
		}
		return true;
	}
	
	/**
	 * 更新列
	 * 
	 * @param table
	 * @param connection
	 * @throws Exception
	 */
	private void updateColumns(CodeTable table, Connection connection, String databaseName) throws Exception {
		// 先清理这个表列的原数据
		if (table.getId() != null) {
			columnService.deleteByTableId(table.getId());
		}

		// 如果表格没有设置过，也清理字段信息
		if (table.getStatus() == Constants.TABLE_NOT_SET) {
			fieldService.deleteByTableId(table.getId());
		}
		// 获取新的列数据
		List<Column> columns = JdbcGenerator.getColumns(connection, table.getCode(), databaseName);
		// 插入到数据库
		for (Column column : columns) {
			column.setTableId(table.getId());
			try {
				this.columnDao.insert(column);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			}
			

			// 只针对未设置的表重置相关字段信息
			if (table.getStatus() == Constants.TABLE_NOT_SET) {
				addField(column);
			} else {// 针对删除已设置表，判断字段是否存在，然后再决定添加与否
				List<Field> fields = fieldService.findByColumnAndTableId(column.getCode(),column.getTableId());
				if (fields.size() == 0) {
					addField(column);
				}
			}
		}
	}
	
	
	/**
	 * 新增字段信息
	 * 
	 * @param column
	 * @throws Exception
	 */
	private void addField(Column column) throws ServiceException {
		Field field = new Field();
		// 列名
		field.setColumn(column.getCode());
		//是否主键
		field.setIsPrimary(column.getIsPrimary());
		// 名称
		field.setName(JdbcGenerator.getFieldName(column.getCode()));
		field.setJdbcType(column.getDataType());
		// 注释
		String remarks = column.getRemarks();
		// 长度
		Integer length = column.getLength();
		// 精度
		Integer precision = column.getDataPrecision();

		String[] remarksArray = createRemarksArray(remarks);
		if (remarksArray != null && remarksArray.length>0) {
			remarks = remarksArray[0];
		}
		field.setRemarks(remarks);

		// 数据类型准备
		DBType dbType = null;
		DBType[] values = DBType.values();
		for (DBType type : values) {
			if (column.getDataType().equalsIgnoreCase(type.toString())) {
				dbType = type;
				break;
			}
		}
		if (dbType == null) {
			throw new ServiceException("数据库类型不存在。类型为：" + column.getDataType() + "");
		}
		// Java类型
		field.setJavaType(dbType.getJavaType().toString());
		// 标签类型
		field.setTagType(dbType.getTagType().toString());
		// 校验类型
		ValidType validType = dbType.getValidType();
		StringBuffer buffer = new StringBuffer();
		if (field.getJavaType().equals(JavaType.Date.toString())) {
			buffer.append(validType.toString()).append("[1,").append(length).append("]");
		} else if (field.getJavaType().equals(JavaType.String.toString())) {
			buffer.append(validType.toString()).append("[1,").append(length / 2).append("]");
		} else {
			buffer.append(validType.toString()).append("[1,").append(length / 2).append("]");
		}
		field.setValidType(buffer.toString());
		// 默认值
		String defaultValue = column.getDefaultValue();
		if (defaultValue == null || defaultValue.isEmpty()) {
			defaultValue = "";
		} else {
			defaultValue = defaultValue.replace("'", "\"");
			if (defaultValue.trim().equals("SYSDATE")) {
				defaultValue = "new Date()";
			} else if (isNumeric(defaultValue) && field.getJavaType().equals(JavaType.Double.toString())) { // 如果是数字并且java类型为浮点型时
				defaultValue += ".0";// 在数字加“.0”?
			}
		}
		field.setDefaultValue(defaultValue);
		// 长度
		field.setLength(length);
		// 精度
		field.setPrecision(precision);
		// 必填
		field.setRequired(Constants.BOOLEAN_NO);
		// 可视
		field.setDisabled(Constants.BOOLEAN_NO);
		// url
		String url = "";
		if (remarksArray != null && remarksArray.length == 2) {
			url = createUrl(remarksArray[1]);
		}
		field.setUrl(url);
		String formatter = "";
		field.setFormatter(formatter);
		// 可编辑
		field.setEditable(Constants.BOOLEAN_NO);
		// 唯一
		field.setUnique(Constants.BOOLEAN_NO);
		// 聚焦
		field.setFocused(Constants.BOOLEAN_NO);
		// 可查询
		field.setQueryable(Constants.BOOLEAN_NO);
		// 表
		field.setTableId(column.getTableId());

		if (column.getCode().toUpperCase().equals("ID")) {
			field.setTagType(TagType.hidden.toString());
			field.setValidType(null);
			field.setDefaultValue("-1");
		}
		this.fieldDao.insert(field);
	}

	@Override
	@Transactional
	public ResponseData deleteProjectOfRelate(String projectId, String userId){
		StringBuilder logDesc = new StringBuilder();
		Project project  = this.getOne(projectId);
		if(project==null){
			return ResponseData.failed("删除失败，项目不存在!");
		}

		if(logDesc.length()>0){
			logDesc.append(",");
		}
		logDesc.append(project.getId());
		int isOnwer = this.projectUserService.countByProjectIdAndUserIdAndIsOwner(project.getId()
				, userId,Constants.IS_OWNER_TRUE);
		if(isOnwer<1){
			return ResponseData.failed("删除失败！只有项目创建者才可以删除项目！");
		}
		this.delete(project);
		this.codeTableService.deleteByProjectId(project.getId());
		this.templateService.deleteByProjectId(project.getId());
		this.nameRuleService.deleteByProjectId(project.getId());
		this.projectUserService.deleteByProjectId(project.getId());
	
		return ResponseData.success("删除项目成功，项目【"+logDesc.toString()+"】");
	}
	
	/**
	 * 创建注释数组
	 * 
	 * @param remarks
	 * @return
	 */
	private String[] createRemarksArray(String remarks) {
		if (remarks == null) {
			return null;
		} else if (remarks.indexOf("。") != -1) {
			return remarks.split("。");
		} else if (remarks.indexOf(".") != -1) {
			return remarks.split(".");
		}
		return null;
	}

	/**
	 * 创建json地址
	 * 
	 * @param str
	 * @return
	 */
	private String createUrl(String str) {
		StringBuffer url = new StringBuffer("");
		String[] options = null;
		if (str.indexOf("；") != -1) {
			options = str.split("；");
		} else if (str.indexOf(";") != -1) {
			options = str.split(";");
		} else {
			return "";
		}

		url.append("[");
		for (int i = 0; i < options.length; i++) {
			String option = options[i];
			int index = -1;
			if (option.indexOf(":") != -1) {
				index = option.indexOf(":");
			} else if (option.indexOf("：") != -1) {
				index = option.indexOf("：");
			} else {
				return "";
			}
			url.append("{");
			url.append("\"value\":");
			String value = option.substring(0, index);
			if (isNumeric(value)) {
				url.append(value);
			} else {
				url.append("\"").append(value).append("\"");
			}
			url.append(",");
			url.append("\"text\":\"").append(option.substring(index + 1)).append("\"");
			url.append("}");
			if (i != options.length - 1) {
				url.append(",");
			}
		}
		url.append("]");

		return url.toString();
	}

	/**
	 * 是否是数字
	 * 
	 * @param str
	 * @return
	 */
	private boolean isNumeric(String str) {
		Pattern pattern = Pattern.compile("[0-9]*");
		return pattern.matcher(str).matches();
	}
}
